﻿using ArtMath.Attribute;
using ArtMath.Component.Line;
using ArtMath.Component.Point;
using ArtMath.Core.Data;
using ArtMath.Core.Helper;
using ArtMath.Flag;
using ArtMath.Helper;
using ArtMath.PointCollection;
using ArtMath.Resource;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Linq;

namespace ArtMath.Component.Polygon
{
    /// <summary>
    /// 平行四边形基类
    /// </summary>
    [Serializable]
    public abstract class ParallelogramBase : PolygonBase
    {
        public ParallelogramBase(SketchPad pad, string name, ToolTypeName toolType, bool addToList = true) : base(pad, name, toolType, addToList)
        {
            for (int i = 0; i < 4; i++)
            {
                Lines.Add(null);
            }
        }
        [Browsable(false)]
        public override List<LineSegmentBase> Lines
        {
            get
            {
                return base.Lines;
            }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}1", "Edge")]
        public LineSegmentBase Line1
        {
            get { return Lines[0]; }
            set { SetLine(0, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}2", "Edge")]
        public LineSegmentBase Line2
        {
            get { return Lines[1]; }
            set { SetLine(1, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}3", "Edge")]
        public LineSegmentBase Line3
        {
            get { return Lines[2]; }
            set { SetLine(2, value); }
        }
        [MultilingualCategory("Structure"), MultilingualDisplayName("{0}4", "Edge")]
        public LineSegmentBase Line4
        {
            get { return Lines[3]; }
            set { SetLine(3, value); }
        }
        public override int ClickTimes
        {
            get
            {
                return 3;
            }
        }
        public override void ComponentBuilding(Base component)
        {
            ShowStatus($"{Resources.Translate("Creating")}{Resources.ColonSeparate}{Name}");
            if (component == Line2)
            {
                PointD tmp = Pad.PxyToXY(Line2.SpareCoordinate);
                double djxlen = Line1.Point1.ToPointD().DistanceTo(tmp);
                Circumference = (Line1.Length + Line2.Length) * 2;
                double ave = (Line1.Length + Line2.Length + djxlen) / 2;
                Area = Math.Sqrt(ave * (ave - Line1.Length) * (ave - Line2.Length) * (ave - djxlen)) * 2;
                BaryCenter = Utility.GetBaryCenter(new PointD[] { Line1.Point1.ToPointD(), Line2.Point1.ToPointD(), tmp, tmp + Line1.Point1.ToPointD() - Line2.Point1.ToPointD() });
            }
            else
            {
                return;
            }
            base.ComponentBuilding(component);
        }
        public override PointCollectionBase[] GetInPointMovingRange(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 1:
                    if (movePoint == Line1.Point1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Line2.Point1.NewXY + Line4.Point1.NewXY - Line3.Point1.NewXY) };
                    }
                    else if (movePoint == Line2.Point1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Line1.Point1.NewXY + Line3.Point1.NewXY - Line4.Point1.NewXY) };
                    }
                    else if (movePoint == Line3.Point1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Line2.Point1.NewXY + Line4.Point1.NewXY - Line1.Point1.NewXY) };
                    }
                    else if (movePoint == Line4.Point1)
                    {
                        return new PointCollectionBase[] { new DiscontinuityPoint(Line1.Point1.NewXY + Line3.Point1.NewXY - Line2.Point1.NewXY) };
                    }
                    break;
            }
            return base.GetInPointMovingRange(movePoint, sender);
        }
        public override void InternalPointMove(PointBase movePoint, Base sender = null)
        {
            switch (CountMovablePoints())
            {
                case 2:
                    if (movePoint == Line1.Point1)
                    {
                        if (Line2.Point1.Movable)
                        {
                            Line2.Point1.Move(movePoint.NewPxy + Line3.Point1.NewPxy - Line4.Point1.NewPxy, true);
                        }
                        else if (Line3.Point1.Movable)
                        {
                            Line3.Point1.Move(Line2.Point1.NewPxy + Line4.Point1.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (Line4.Point1.Movable)
                        {
                            Line4.Point1.Move(movePoint.NewPxy + Line3.Point1.NewPxy - Line2.Point1.NewPxy, true);
                        }
                    }
                    else if (movePoint == Line2.Point1)
                    {
                        if (Line1.Point1.Movable)
                        {
                            Line1.Point1.Move(movePoint.NewPxy + Line4.Point1.NewPxy - Line3.Point1.NewPxy, true);
                        }
                        else if (Line3.Point1.Movable)
                        {
                            Line3.Point1.Move(movePoint.NewPxy + Line4.Point1.NewPxy - Line1.Point1.NewPxy, true);
                        }
                        else if (Line4.Point1.Movable)
                        {
                            Line4.Point1.Move(Line1.Point1.NewPxy + Line3.Point1.NewPxy - movePoint.NewPxy, true);
                        }
                    }
                    else if (movePoint == Line3.Point1)
                    {
                        if (Line1.Point1.Movable)
                        {
                            Line1.Point1.Move(Line2.Point1.NewPxy + Line4.Point1.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (Line2.Point1.Movable)
                        {
                            Line2.Point1.Move(movePoint.NewPxy + Line1.Point1.NewPxy - Line4.Point1.NewPxy, true);
                        }
                        else if (Line4.Point1.Movable)
                        {
                            Line4.Point1.Move(movePoint.NewPxy + Line1.Point1.NewPxy - Line2.Point1.NewPxy, true);
                        }
                    }
                    else if (movePoint == Line4.Point1)
                    {
                        if (Line1.Point1.Movable)
                        {
                            Line1.Point1.Move(movePoint.NewPxy + Line2.Point1.NewPxy - Line3.Point1.NewPxy, true);
                        }
                        else if (Line2.Point1.Movable)
                        {
                            Line2.Point1.Move(Line1.Point1.NewPxy + Line3.Point1.NewPxy - movePoint.NewPxy, true);
                        }
                        else if (Line3.Point1.Movable)
                        {
                            Line3.Point1.Move(movePoint.NewPxy + Line2.Point1.NewPxy - Line1.Point1.NewPxy, true);
                        }
                    }
                    return;
            }
            base.InternalPointMove(movePoint, sender);
        }
        protected virtual PointCollectionBase[] collections()
        {
            return Universal.GenerateInstanceArray();
        }
        public override bool CanDrawVirtual
        {
            get
            {
                return Line2 != null;
            }
        }
        public override void PaintVirtualObjects(Graphics gra)
        {
            if (CanDrawVirtual)
            {
                PointD tmp = Line2.SpareCoordinate_ + Line1.Point1.Pxy - Line2.Point1.Pxy;
                gra.FillPolygon(Core.Helper.Painter.VirtualBrush, new PointF[] { Line1.Point1.Pxy.ToPointF(), Line2.Point1.Pxy.ToPointF(), Line2.SpareCoordinate_.ToPointF(), tmp.ToPointF() });
                gra.DrawLineSegment(Line2.SpareCoordinate_, tmp);
                gra.DrawLineSegment(tmp, Line1.Point1.Pxy);
                gra.DrawPoint(tmp);
            }
        }
        public override void CreateComponents()
        {
            if (Line1 == null)
            {
                Line1 = new TwoPointsLineSegment(Pad, $"{Resources.Translate("Edge")}1", false) { SpareCoordinate_ = SpareCoordinate_, };
                Line1.CreateComponents($"{Resources.Translate("Edge")}1{Resources.Join}{Resources.Translate("EndPoint")}1/{Resources.Translate("Edge")}4{Resources.Join}{Resources.Translate("EndPoint")}2");
            }
            else if (Line2 == null)
            {
                Line1.CreateComponents($"{Resources.Translate("Edge")}2{Resources.Join}{Resources.Translate("EndPoint")}1/{Resources.Translate("Edge")}1{Resources.Join}{Resources.Translate("EndPoint")}2");
                Line2 = new TwoPointsLineSegment(Pad, $"{Resources.Translate("Edge")}2", false)
                {
                    AllowFix = ToolType == ToolTypeName.pxsbx || ToolType == ToolTypeName.lx
                };
                Line2.CreateComponents(Line1.Point2);
            }
            else
            {
                Line2.CreateComponents($"{Resources.Translate("Edge")}3{Resources.Join}{Resources.Translate("EndPoint")}1/{Resources.Translate("Edge")}2{Resources.Join}{Resources.Translate("EndPoint")}2", collections());
                Line3 = new TwoPointsLineSegment(Pad, $"{Resources.Translate("Edge")}3", false) { AllowFix = false };
                Line3.CreateComponents(Line2.Point2);
                Flags.ShieldCtrl(() => { Line3.CreateComponents(Pad.CreatePoint($"{Resources.Translate("Edge")}4{Resources.Join}{Resources.Translate("EndPoint")}1/{Resources.Translate("Edge")}3{Resources.Join}{Resources.Translate("EndPoint")}2", Line3.Point1.Pxy + Line1.Point1.Pxy - Line2.Point1.Pxy, false)); });
                Line4 = new TwoPointsLineSegment(Pad, $"{Resources.Translate("Edge")}4", false) { AllowFix = false };
                Line4.CreateComponents(Line3.Point2, Line1.Point1);
                base.CreateComponents();
            }
        }
    }
}
